package simpledb.index;

import simpledb.storage.Field;
import simpledb.storage.RecordId;

import java.io.Serializable;

/**
 * BTreeEntry 表示 B+ 树内部节点中的一个条目。
 *
 * 每个条目包含：
 * - 一个键（key）
 * - 左子节点页面 ID（leftChild）
 * - 右子节点页面 ID（rightChild）
 *
 * 它被 BTreeInternalPage 使用来遍历节点中存储的条目。
 *
 * 所有左子节点中的数据应小于等于该条目的键；
 * 所有右子节点中的数据应大于等于该条目的键。
 *
 * 注意：修改一个 BTreeEntry 对象并不会自动更新磁盘页面上的数据。
 * 要使更改生效，必须调用 BTreeInternalPage.updateEntry() 方法。
 *
 * @see BTreeInternalPage
 * @see BTreeInternalPage#updateEntry(BTreeEntry)
 */
public class BTreeEntry implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 当前条目的键值
     */
    private Field             key;

    /**
     * 左子节点页面 ID
     */
    private BTreePageId       leftChild;

    /**
     * 右子节点页面 ID
     */
    private BTreePageId       rightChild;

    /**
     * 当前条目的记录 ID（即它在页面中的位置）。
     * 如果该条目未实际存储在某个页面中，则为 null。
     */
    private RecordId          rid;

    /**
     * 构造一个新的 BTreeEntry 实例。
     *
     * @param key       条目键值
     * @param leftChild 左子节点页面 ID
     * @param rightChild 右子节点页面 ID
     */
    public BTreeEntry(Field key, BTreePageId leftChild, BTreePageId rightChild) {
        this.key = key;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }

    /**
     * 获取当前条目的键值。
     *
     * @return 键值
     */
    public Field getKey() {
        return key;
    }

    /**
     * 获取左子节点页面 ID。
     *
     * @return 左子节点页面 ID
     */
    public BTreePageId getLeftChild() {
        return leftChild;
    }

    /**
     * 获取右子节点页面 ID。
     *
     * @return 右子节点页面 ID
     */
    public BTreePageId getRightChild() {
        return rightChild;
    }

    /**
     * 获取该条目的记录 ID，表示其在 BTreeFile 中的位置。
     * 若此条目未存储在任何页面中，返回 null。
     *
     * @return 记录 ID
     */
    public RecordId getRecordId() {
        return rid;
    }

    /**
     * 设置新的键值。
     * 注意：修改后需要调用 BTreeInternalPage.updateEntry() 才会真正更新页面内容。
     *
     * @param key 新的键值
     * @see BTreeInternalPage#updateEntry(BTreeEntry)
     */
    public void setKey(Field key) {
        this.key = key;
    }

    /**
     * 设置新的左子节点页面 ID。
     * 注意：修改后需要调用 updateEntry() 才会生效。
     *
     * @param leftChild 新的左子节点
     * @see BTreeInternalPage#updateEntry(BTreeEntry)
     */
    public void setLeftChild(BTreePageId leftChild) {
        this.leftChild = leftChild;
    }

    /**
     * 设置新的右子节点页面 ID。
     * 注意：修改后需要调用 updateEntry() 才会生效。
     *
     * @param rightChild 新的右子节点
     * @see BTreeInternalPage#updateEntry(BTreeEntry)
     */
    public void setRightChild(BTreePageId rightChild) {
        this.rightChild = rightChild;
    }

    /**
     * 设置该条目的记录 ID。
     *
     * @param rid 新的记录 ID
     */
    public void setRecordId(RecordId rid) {
        this.rid = rid;
    }

    /**
     * 返回当前条目的字符串表示形式。
     * 格式为：[左子节点页号|键值|右子节点页号]
     *
     * @return 字符串表示
     */
    public String toString() {
        return "[" + leftChild.getPageNumber() + "|" + key + "|" + rightChild.getPageNumber() + "]";
    }
}
